/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include "Matrix.h"
#include "../utility/MacroTool.h"

namespace SkyEngine2d
{
	bool Matrix4X4::operator==(const Matrix4X4 & mat)
	{
		USING_NS_DX;
	
		auto x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._11));
		auto x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._21));
		auto x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._31));
		auto x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._41));
	
		auto y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_11));
		auto y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_21));
		auto y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_31));
		auto y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_41));
	
		return
			XMVector4Equal(x1, y1) &&
			XMVector4Equal(x2, y2) &&
			XMVector4Equal(x3, y3) &&
			XMVector4Equal(x4, y4);
	}
	
	bool Matrix4X4::operator!=(const Matrix4X4 & mat)
	{
		USING_NS_DX;
	
		auto x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&_11));
		auto x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&_21));
		auto x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&_31));
		auto x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&_41));
	
		auto y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._11));
		auto y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._21));
		auto y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._31));
		auto y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._41));
	
		return
			(XMVector4NotEqual(x1, y1) ||
			 XMVector4NotEqual(x2, y2) ||
			 XMVector4NotEqual(x3, y3) ||
			 XMVector4NotEqual(x4, y4))==true;
	}
	
	Matrix4X4& Matrix4X4::operator+=(const Matrix4X4 & mat)
	{
		USING_NS_DX;
	
		XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
		XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
		XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
		XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
	
		XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._11));
		XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._21));
		XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._31));
		XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._41));
	
		x1 = XMVectorAdd(x1, y1);
		x2 = XMVectorAdd(x2, y2);
		x3 = XMVectorAdd(x3, y3);
		x4 = XMVectorAdd(x4, y4);
	
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
		return *this;
	}
	
	Matrix4X4& Matrix4X4::operator-=(const Matrix4X4 & mat)
	{
		USING_NS_DX;
	
		XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
		XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
		XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
		XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
	
		XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._11));
		XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._21));
		XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._31));
		XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&mat._41));
	
		x1 = XMVectorSubtract(x1, y1);
		x2 = XMVectorSubtract(x2, y2);
		x3 = XMVectorSubtract(x3, y3);
		x4 = XMVectorSubtract(x4, y4);
	
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
		XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
		return *this;
	}
	
	bool Matrix4X4::operator==(const Matrix4X4 & mat) const
	{
		USING_NS_DX;
	
		auto x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._11));
		auto x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._21));
		auto x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._31));
		auto x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&mat._41));
	
		auto y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_11));
		auto y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_21));
		auto y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_31));
		auto y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4 *>(&this->_41));
	
		return
			XMVector4Equal(x1, y1) &&
			XMVector4Equal(x2, y2) &&
			XMVector4Equal(x3, y3) &&
			XMVector4Equal(x4, y4);
	}
	
	void Matrix4X4::transformVector(const Vector3  & pos_in, Vector3 * pos_out)const
	{
		*pos_out = XMVector4Transform(Vector4(pos_in.x, pos_in.y, pos_in.z, 1), *this);
	}
	
	Matrix4X4 Matrix4X4::Invert() const
	{
		USING_NS_DX;
	
		XMMATRIX M = XMLoadFloat4x4(this);
		Matrix4X4 R;
		XMVECTOR det;
		XMStoreFloat4x4(&R, XMMatrixInverse(&det, M));
		return R;
	}
	
	Matrix4X4 Matrix4X4::IdentityMat=Matrix4X4();
	
}
